package com.coupon.gui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.persistence.RollbackException;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Category;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.TransactionSystemException;

import com.coupon.bl.Constant;
import com.coupon.bl.CouponException;
import com.coupon.bl.UserHandler;
import com.coupon.dal.entity.Coupon;
import com.coupon.dal.entity.User;
import com.icesoft.faces.component.selectinputtext.SelectInputText;

public class LoginBean {

	private UserHandler userHandler = null;
	// private CouponDataTable couponDataTable = null;
	private String email;

	// result table helper field
	private String hiddenGroupId;

	// pagination for result table
	private Boolean enablePagination = false;
	private Integer itemPerPage = 3;

	// dropdown- area
	private String selectedComponent;

	// auto complete parameters
	private String selectedGroup; // auto complete text
	private Integer couponListLength = 10;
	private Coupon selectedCoupon; // Coupon which has been selected at the auto
									// complete drop down
	private List<SelectItem> couponMatchPossibilities; // hold Possible coupons as
											// SelectItem(Coupon,coupon.getCompanyName)
											// list
	private ArrayList<SelectItem> couponsAutoCompleteListObject; // hold All coupon list as
														// SelectItem(Coupon,coupon.getCompanyName)
														// list
	private ArrayList<Coupon> mockList = null;

	static final Logger log = Logger.getLogger(LoginBean.class);

	// Ctor for Mock usage
	public LoginBean() {
		try {
			log.info("init loginBean - mock usage");
			synchronized (this) {
				init();
			}
		} catch (Exception e) {
			log.error("init loginBean - mock usage:" + e.getMessage());
		}
	}

	// init coupons mock till get from DB
	// we create autoCompleteObject (Coupon=value,Coupon_Company_Name=label) in
	// the drop down auto complete
	@SuppressWarnings("unchecked")
	public void init() {
		mockList = new ArrayList<Coupon>();
		initMockCoupons();
		couponsAutoCompleteListObject = new ArrayList(mockList.size());
		Iterator<Coupon> iter = mockList.iterator();
		Coupon coupon;
		while (iter.hasNext()) {
			coupon = iter.next();
			//couponsAutoCompleteListObject.add(new SelectItem(coupon, coupon.getDealCompanyName()));
			couponsAutoCompleteListObject.add(new SelectItem( coupon.getDealCompanyName(), coupon.getDealCompanyName()));
		}
		Collections.sort(couponsAutoCompleteListObject, LABEL_COMPARATOR);
	}

	// init mock coupons
	public void initMockCoupons() {
		if (mockList.size() == 0) {
			for (int i = 0; i < 10; i++) {
				Coupon coupon = new Coupon();
				coupon.setDealDescription("desc" + i);
				coupon.setDealCompanyName("aroma" + i);
				coupon.setId(Long.valueOf(i * 10));
				coupon.setOriginalPrice(Double.valueOf(i));
				mockList.add(coupon);
			}
		}
	}

	// /////////////////////// START AUTO COMPLETE CODE

	public void selectInputValueChanged(ValueChangeEvent event) {
		if (event.getComponent() instanceof SelectInputText) {

			// get the number of displayable records from the component
			SelectInputText autoComplete = (SelectInputText) event
					.getComponent();
			// get the new value typed by component user.
			String newWord = (String) event.getNewValue();

			couponMatchPossibilities = generateCouponMatches(newWord,
					couponListLength);

			// if there is a selected item then find the city object of the
			// same name
			if (autoComplete.getSelectedItem() != null) {
				selectedCoupon = (Coupon) autoComplete.getSelectedItem()
						.getValue();
				// fire effect to draw attention
				// valueChangeEffect.setFired(false);
			}
			// if there was no selection we still want to see if a proper
			// city was typed and update our selectedCity instance.
			else {
				Coupon tmp = findCouponMatchByCompanyName(newWord);
				if (tmp != null) {
					selectedCoupon = tmp;
					// fire effect to draw attention
					// valueChangeEffect.setFired(false);
				}
			}

		}
	}

	private Coupon findCouponMatchByCompanyName(String couponCompanyName) {
		if (couponMatchPossibilities != null) {
			SelectItem couponSelectedItem;
			for (int i = 0, max = couponMatchPossibilities.size(); i < max; i++) {
				couponSelectedItem = (SelectItem) couponMatchPossibilities
						.get(i);
				if (couponSelectedItem.getLabel().compareToIgnoreCase(
						couponCompanyName) == 0) {
					return (Coupon) couponSelectedItem.getValue();
				}
			}
		}
		return null;
	}

	// compare according to label (deal company name)
	private static final Comparator LABEL_COMPARATOR = new Comparator() {
		@Override
		// compare method for city entries.
		public int compare(Object o1, Object o2) {
			SelectItem selectItem1 = (SelectItem) o1;
			SelectItem selectItem2 = (SelectItem) o2;
			// compare ignoring case, give the user a more automated feel when
			// typing
			return selectItem1.getLabel().compareToIgnoreCase(
					selectItem2.getLabel());
		}

	};

	public ArrayList generateCouponMatches(String searchWord, int maxMatches) {
		ArrayList matchList = new ArrayList(maxMatches);

		// ensure the autocomplete search word is present
		if ((searchWord == null) || (searchWord.trim().length() == 0)) {
			return matchList;
		}

		try {
			SelectItem searchItem = new SelectItem("", searchWord);
			int insert = Collections
					.binarySearch(couponsAutoCompleteListObject, searchItem,
							LABEL_COMPARATOR);

			// less then zero if we have a partial match
			if (insert < 0) {
				insert = Math.abs(insert) - 1;
			} else {
				// If there are duplicates in a list, ensure we start from the
				// first one
				if (insert != couponsAutoCompleteListObject.size()
						&& LABEL_COMPARATOR.compare(searchItem,
								couponsAutoCompleteListObject.get(insert)) == 0) {
					while (insert > 0
							&& LABEL_COMPARATOR.compare(searchItem,
									couponsAutoCompleteListObject
											.get(insert - 1)) == 0) {
						insert = insert - 1;
					}
				}
			}

			for (int i = 0; i < maxMatches; i++) {
				// quit the match list creation if the index is larger than
				// max entries in the cityDictionary if we have added
				// maxMatches.
				if ((insert + i) >= couponsAutoCompleteListObject.size()
						|| i >= maxMatches) {
					break;
				}
				matchList.add(couponsAutoCompleteListObject.get(insert + i));
			}
		} catch (Throwable e) {
			log.error("generateCouponMatches:" + e.getMessage());
		}
		// assign new matchList
		return matchList;
	}

	// ////////////////////// END AUTO COMPLETE CODE

	// get match coupon details in table
	public void submitSearch() {
		
		System.out.println("text="+this.getSelectedGroup());
		System.out.println("area=" +this.getSelectedComponent());

	}

	public Boolean getEnablePagination() {
		if (this.couponMatchPossibilities != null
				&& this.couponMatchPossibilities.size() > itemPerPage)
			return true;
		return false;
	}

	// get the coupon Id and add to user
	public void join(ActionEvent actionEvent) {
		/*
		 * CODE EXAMPLE FOR DORI FacesContext facesContext =
		 * FacesContext.getCurrentInstance(); ExternalContext externalContext =
		 * facesContext.getExternalContext(); HttpServletRequest req
		 * =(HttpServletRequest)externalContext.getRequest(); String groupId
		 * =req.getParameter("hiddenId");
		 */
		String groupId = this.getHiddenGroupId();
		this.setHiddenGroupId("");
		log.info("group=" + groupId);
	}

	// currently not in use
	public String submitLogin() {
		return addUser();
	}

	public String addUser() {
		log.info("adding new user");
		User userEntity = new User();
		userEntity.setEmail(this.getEmail());
		try {
			userHandler.addUser(userEntity);
			return "success";
		} catch (CouponException e) {
			FacesContext context = FacesContext.getCurrentInstance();
			FacesMessage message = new FacesMessage();
			message.setSeverity(FacesMessage.SEVERITY_INFO);
			message.setSummary(e.getMessage());
			context.addMessage(null, message);
			return "failed";
		} catch (Exception ee) {
			FacesContext context = FacesContext.getCurrentInstance();
			FacesMessage message = new FacesMessage();
			message.setSeverity(FacesMessage.SEVERITY_INFO);
			message.setSummary(Constant.USER_WITH_SAME_EMAIL_ALREADY_EXIST);
			context.addMessage(null, message);
			return "failed";
		}
	}

	@Required
	public void setUserHandler(UserHandler userHandler) {
		this.userHandler = userHandler;
	}

	/*
	 * @Required public void setCouponDataTable(CouponDataTable couponDataTable)
	 * { this.couponDataTable = couponDataTable; }
	 */

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getSelectedGroup() {
		return selectedGroup;
	}

	public void setSelectedGroup(String selectedGroup) {
		this.selectedGroup = selectedGroup;
	}

	public String getHiddenGroupId() {
		return hiddenGroupId;
	}

	public void setHiddenGroupId(String hiddenGroupId) {
		this.hiddenGroupId = hiddenGroupId;
	}

	public Integer getCouponListLength() {
		return couponListLength;
	}

	public List getCouponMatchPossibilities() {
		return couponMatchPossibilities;
	}

	public Integer getItemPerPage() {
		return itemPerPage;
	}

	public ArrayList<Coupon> getMockList() {
		return mockList;
	}

	public String getSelectedComponent() {
		return selectedComponent;
	}

	public void setSelectedComponent(String selectedComponent) {
		this.selectedComponent = selectedComponent;
	}

	public List<SelectItem> getComponentItems() {
		List<SelectItem> arr = new ArrayList<SelectItem>();
		arr.add(new SelectItem("101", "name1"));
		arr.add(new SelectItem("102", "name2"));
		return arr;
	}

}
